/*
 * Declaracao da gramatica da linguagem de programacao LUA.
 *
 * Data de criacao: 20/05/2013
 * Ultima modificacao: 03/06/2013
 *
 * Grupo:
 * Fabio Gunkel         316520
 * Lucas Oliveira David 407917
 *
 */
 
grammar Lua;


/*
 * LEXICO
 */

// palavras chave

REPEAT
    : 'repeat';
DO
    : 'do';
UNTIL
    : 'until';
WHILE    
    : 'while';

IF       
    : 'if';
THEN     
    : 'then';
ELSE     
    : 'else';
ELSEIF  
    : 'elseif';
END     
    : 'end';

FOR      
    : 'for';
FUNCTION 
    : 'function';
RETURN  
    : 'return';
BREAK
    : 'break';

IN       
    : 'in'; 
LOCAL    
    : 'local';
NIL      
    : 'nil';
NULL
    : 'null';
FALSE
    : 'false';
TRUE     
    : 'true';

// simbolos reservados
PONTO
    : '.';
DOI_PON
    : ':';
VIRGULA
    : ',';
ATRIB
    : '=';
PON_VIR
    : ';';
RETIC
    : '...';
ASPAS
    : '\'';
ABR_COL
    : '[';
FEC_COL
    : ']';
ABR_PAR
    : '(';
FEC_PAR
    : ')';
ABR_CHA
    : '{';
FEC_CHA
    : '}';


// ignorar espacos em branco
WS
    : (' '|'\t'|'\n'|'\r')+ {skip();}
    ;

// ignorar caracteres apos '//' ate o fim da linha
Comentario
    : ('//' | '--') ~('\n'|'\r')* '\r'? '\n' { skip(); }
    ;

// todos os nomes, iniciando com uma letra ou _
Nome
    : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
    ;
// digitos, separados por PONTO. Todas as combinacoes valem:
// 1.0 / .0 / 1, exceto PONTO
Numero
    : ('0'..'9')* PONTO ('0'..'9')+ |
      ('0'..'9')+ PONTO ('0'..'9')* |
      ('0'..'9')+
    ;
// tudo delimitado por '', exceto a propria aspa
Cadeia
    : ASPAS (~('\''|'\\'))* ASPAS
    ;

// operadores aritmeticos
MAIS
    : '+';
MENOS
    : '-';
MUL
    : '*';
DIV
    : '/';
EXP
    : '^';
MOD
    : '%';
CONCAT
    : '..';
// operadores logicos
MENOR
    : '<';
MENOR_IGUAL
    : '<=';
MAIOR
    : '>';
MAIOR_IGUAL
    : '>=';
IGUAL
    : '==';
DIFE
    : '~=';
AND      
    : 'and';
OR       
    : 'or';

// opunario
NOT      
    : 'not'; 

CERQ
    : '#';


/*
 * SINTATICO
 */

programa // regra principal
    : trecho
    ;
trecho  // um conjunto de comandos separados por ponto e virgula (opcional)
        // e finalizado com um ultimocomando (opcional)
    : (comando (PON_VIR)?)* (ultimocomando (PON_VIR)?)?
    ;
bloco
    : trecho
    ;
comando // lista de variaveis, chamada de funcao, while, repeat, if,
        // declaracao de funcoes etc
    : listavar ATRIB listaexp | chamadadefuncao | DO bloco END |
      WHILE exp DO bloco END | REPEAT bloco UNTIL exp |
      IF exp THEN bloco (ELSEIF exp THEN bloco)* (ELSE bloco)? END |
      FOR Nome ATRIB exp VIRGULA exp (VIRGULA exp)? DO bloco END |
      FOR listadenomes IN listaexp DO bloco END |
      FUNCTION nomedafuncao corpodafuncao |
      LOCAL FUNCTION Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.FUNCAO); } corpodafuncao |
      LOCAL listadenomes (ATRIB listaexp)?;
ultimocomando
    : RETURN (listaexp)? | BREAK
    ;
nomedafuncao // nome.nome : nome
    : Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.FUNCAO); }
    (PONTO Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.FUNCAO); })*
    (DOI_PON Nome)?
    ;
listavar // lista de uma ou mais variaveis separadas por ','
    : var (VIRGULA var)*
    ;
var      // declaracao da variavel no seguinte estilo:
         // nome, nome[expressao], nome.nome.(...).nome, nome[expressao].nome
    : Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.VARIAVEL); } |
      expprefixo2 ABR_COL exp FEC_COL |
      expprefixo2 PONTO Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.VARIAVEL); }
    ;
listadenomes // lista de nomes separados por ','
    : Nome (VIRGULA Nome)*
    ;
listaexp     // lista de exp separados por virgula, minimo de uma exp
    : (exp VIRGULA)* exp
    ;
exp
    : NIL | FALSE | TRUE | Numero | Cadeia | RETIC | funcao |
      expprefixo | construtortabela | exp opbin exp | opunaria exp
    ;
chamadadefuncao
    : expprefixo2 args | expprefixo2 DOI_PON Nome args
    ;

expprefixo
    : var | chamadadefuncao | ABR_PAR exp FEC_PAR
    ;
expprefixo2
    : Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.VARIAVEL); } 
      ( ABR_COL exp FEC_COL | 
        PONTO Nome { TabelaDeSimbolos.adicionarSimbolo($Nome.text,Tipo.VARIAVEL); }
      )*
    ;

args // argumentos para funcoes
    : ABR_PAR (listaexp)? FEC_PAR | construtortabela | Cadeia
    ;
funcao // decalaracao de uma funcao
    : FUNCTION corpodafuncao
    ;
corpodafuncao // corpo de declaracao da funcao
    : ABR_PAR (listapar)? FEC_PAR bloco END
    ;
listapar // lista de parametros na declaracao de uma funcao
    : listadenomes (VIRGULA RETIC)? | RETIC
    ;
construtortabela
    : ABR_CHA (listadecampos)? FEC_CHA
    ;
listadecampos
    : campo (separadordecampos campo)* (separadordecampos)?
    ;
campo
    : ABR_COL exp FEC_COL ATRIB exp | Nome ATRIB exp | exp
    ;
separadordecampos // delimitadores ',' e ';'
    : VIRGULA | PON_VIR
    ;
opbin // operadores binarios
    : MAIS | MENOS | MUL | DIV | EXP | MOD | CONCAT |
      MENOR | MENOR_IGUAL | MAIOR | MAIOR_IGUAL | IGUAL | DIFE |
      AND | OR
    ;
opunaria // operadores unarios
    : MENOS | NOT | CERQ
    ;